package com.huishi.ui;

import com.huishi.entity.DataSource;
import com.huishi.handler.thread.task.RecordDataXTaskInfo;
import com.huishi.mapper.DataXTaskInfoMapper;
import com.huishi.service.DataSyncService;
import com.huishi.handler.thread.ThreadDataKeeper;
import com.huishi.handler.thread.task.Reader;
import com.huishi.handler.thread.task.Writer;
import com.huishi.ui.component.DataTaskRecordUI;
import com.huishi.ui.component.IncrementalSyncDialog;
import com.huishi.ui.component.ProgressDialog;
import com.huishi.util.DBUtils;
import com.huishi.util.IdGeneratorSnowflake;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 数据同步UI
 */
//@Component
@Slf4j
@Data
public class DataSyncUI extends JFrame {

    @Autowired
    private ScheduledExecutorService scheduler;

    @Autowired
    private DataSyncService dataSyncService;

    @Autowired
    private DataXTaskInfoMapper dataXTaskInfoMapper;

    @Autowired
    private IdGeneratorSnowflake idGenerator;

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor executor;

    @Autowired
    private ThreadDataKeeper threadDataKeeper;

    @Autowired
    private FunctionSelectionUI functionSelectionUI;
    @Autowired
    private IncrementalSyncDialog incrementalSyncDialog;
    @Autowired
    private DataTaskRecordUI dataTaskRecordUI;

    private JComboBox<DataSource> sourceConnCombo; // 源连接下拉框
    private JComboBox<String> sourceDBCombo; // 源库下拉框
    private JPanel sourceTablePanel; // 源库表
    private List<String> tables = new ArrayList<>(); // 源表名

    private JComboBox<DataSource> targetConnCombo; // 目标连接下拉框
    private JComboBox<String> targetDBCombo; // 目标库下拉框
    private JPanel targetTablePanel; // 目标库表


    @PostConstruct
    public void init() {
        scheduler.submit(this::intiData);
//        intiData();
        log.info("数据同步UI数据初始化成功");
    }

    public DataSyncUI() {
        setTitle("数据同步备份");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                functionSelectionUI.setVisible(true);
            }
        });
        setSize(600, 500);
        setLocationRelativeTo(null); // 窗口居中显示，要在设置size后面

        // 主面板
        JPanel mainPanel = new JPanel(new BorderLayout());
        add(mainPanel);

        // 源 和 目标 面板
        JPanel sourceTargetPanel = new JPanel(new GridLayout(1, 2, 10, 10));
        mainPanel.add(sourceTargetPanel, BorderLayout.CENTER);

        // 源面板==========================
        JPanel sourcePanel = new JPanel(new BorderLayout(1, 15));
        sourceTargetPanel.add(sourcePanel);

        // 源头部面板
        JPanel sourceTopPanel = new JPanel(new GridLayout(5, 1, 1, 1));
        sourcePanel.add(sourceTopPanel, BorderLayout.NORTH);

        sourceTopPanel.add(new JLabel("源", SwingConstants.CENTER));

        sourceTopPanel.add(new JLabel("连接:"));
        sourceConnCombo = new JComboBox<>();
        sourceTopPanel.add(sourceConnCombo);


        sourceTopPanel.add(new JLabel("数据库:"));
        sourceDBCombo = new JComboBox<>();
        sourceTopPanel.add(sourceDBCombo);

        // 源表
        sourceTablePanel = new JPanel();
        sourceTablePanel.setLayout(new BoxLayout(sourceTablePanel, BoxLayout.Y_AXIS));
        JScrollPane sourceTableScroll = new JScrollPane(sourceTablePanel);
        sourcePanel.add(sourceTableScroll, BorderLayout.CENTER);

        // 目标面板 ========================
        JPanel targetPanel = new JPanel(new BorderLayout(1, 15));
        sourceTargetPanel.add(targetPanel);

        // 目标头部
        JPanel targetTopPanel = new JPanel(new GridLayout(5, 1, 1, 1));
        targetPanel.add(targetTopPanel, BorderLayout.NORTH);

        targetTopPanel.add(new JLabel("目标", SwingConstants.CENTER));

        targetTopPanel.add(new JLabel("连接:"));
        targetConnCombo = new JComboBox<>();
        targetTopPanel.add(targetConnCombo);

        targetTopPanel.add(new JLabel("数据库:"));
        targetDBCombo = new JComboBox<>();
        targetTopPanel.add(targetDBCombo);

        // 目标表
        targetTablePanel = new JPanel();
        targetTablePanel.setLayout(new BoxLayout(targetTablePanel, BoxLayout.Y_AXIS));
        JScrollPane targetTableScroll = new JScrollPane(targetTablePanel);
        targetPanel.add(targetTableScroll, BorderLayout.CENTER);


        // 底部菜单栏=================
        JPanel buttonPanel = new JPanel();
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        JButton selectAllButton = new JButton("全选");
        selectAllButton.addActionListener(e -> {
            for (int i = 0; i < sourceTablePanel.getComponentCount(); i++) {
                ((JCheckBox) sourceTablePanel.getComponent(i)).setSelected(true);
            }
        });
        buttonPanel.add(selectAllButton);

        JButton deselectAllButton = new JButton("全部取消选择");
        deselectAllButton.addActionListener(e -> {
            for (int i = 0; i < sourceTablePanel.getComponentCount(); i++) {
                ((JCheckBox) sourceTablePanel.getComponent(i)).setSelected(false);
            }
        });
        buttonPanel.add(deselectAllButton);

        JButton fullSyncButton = new JButton("全量同步");
        fullSyncButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                fullSync();
            }
        });
        buttonPanel.add(fullSyncButton);

        JButton increaseSyncButton = new JButton("增量同步");
        increaseSyncButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                increaseSync();
            }
        });
        buttonPanel.add(increaseSyncButton);

        JButton closeButton = new JButton("关闭");
        closeButton.addActionListener(e -> {
            this.dispose();
            functionSelectionUI.setVisible(true);
        });
        buttonPanel.add(closeButton);

        JButton recordButton = new JButton("记录");
        recordButton.addActionListener(e -> {
            this.dispose();
            dataTaskRecordUI.setVisible(true);
        });
        buttonPanel.add(recordButton);

        // Show the frame
        setVisible(false);
        log.info("数据同步UI创建成功");
    }


    /**
     * 初始化数据
     * 源连接下拉框、目标连接下拉框
     */
    private void intiData() {
        List<DataSource> allDataSource = dataSyncService.getAllDataSource();

        for (DataSource dataSource : allDataSource) {
            sourceConnCombo.addItem(dataSource);
            targetConnCombo.addItem(dataSource);
        }
        sourceConnCombo.setSelectedIndex(-1);
        targetConnCombo.setSelectedIndex(-1);

        // 添加 ItemListener 事件
        sourceConnCombo.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                this.sourceDataConnSelected(((DataSource) e.getItem()));
            }
        });

        targetConnCombo.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                this.targetDataConnSelected(((DataSource) e.getItem()));
            }
        });
    }

    /**
     * 源数据连接选中
     * 更新 源库 和 源库表
     *
     * @param sourceData 数据源信息
     */
    private void sourceDataConnSelected(DataSource sourceData) {

        // 1清空旧数据
        sourceDBCombo.removeAllItems();
        sourceTablePanel.removeAll();

        // 2设置源数据库
        if (sourceData.getSchema() != null) sourceDBCombo.addItem(sourceData.getSchema());

        // 3设置源数据表名
        String executedSql = "SELECT table_name,table_comment FROM information_schema.TABLES " +
                "WHERE table_schema = \'" + sourceData.getSchema() + "\' ORDER BY create_time DESC";

        String sourceUrl = null;
        if ("mysql".equalsIgnoreCase(sourceData.getSourceType()))
            sourceUrl = "jdbc:mysql://" + sourceData.getIp() + ":" + sourceData.getPort() + "/" + sourceData.getSchema() +
                    "?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&connectTimeout=5000";

        try (Connection connection = DriverManager.getConnection(sourceUrl, sourceData.getUserName(), sourceData.getPassword());
             PreparedStatement preparedStatement = connection.prepareStatement(executedSql);
             ResultSet resultSet = preparedStatement.executeQuery()) {

            // 处理结果集
            while (resultSet.next()) {
                String tableName = resultSet.getString("table_name");
                sourceTablePanel.add(new JCheckBox(tableName));
            }

        } catch (SQLException e) {
            log.error("源数据源选中报错：", e);
            JOptionPane.showMessageDialog(null,
                    "错误：" + DBUtils.getLastThrowable(e).getMessage(),
                    "结果", JOptionPane.ERROR_MESSAGE);
        }

        // 4更新面板
        sourceTablePanel.revalidate();
        sourceTablePanel.repaint();
    }

    /**
     * 目标数据连接选中
     * 更新 目标库 和 目标库表
     *
     * @param sourceData 数据源信息
     */
    private void targetDataConnSelected(DataSource sourceData) {

        // 1清空旧数据
        targetDBCombo.removeAllItems();
        targetTablePanel.removeAll();

        // 2设置源数据库
        if (sourceData.getSchema() != null) targetDBCombo.addItem(sourceData.getSchema());

        // 3设置源数据表名
        String executedSql = "SELECT table_name,table_comment FROM information_schema.TABLES " +
                "WHERE table_schema = \'" + sourceData.getSchema() + "\' ORDER BY create_time DESC";

        String sourceUrl = null;
        if ("mysql".equalsIgnoreCase(sourceData.getSourceType()))
            sourceUrl = "jdbc:mysql://" + sourceData.getIp() + ":" + sourceData.getPort() + "/" + sourceData.getSchema() + "?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8";

        try (Connection connection = DriverManager.getConnection(sourceUrl, sourceData.getUserName(), sourceData.getPassword());
             PreparedStatement preparedStatement = connection.prepareStatement(executedSql);
             ResultSet resultSet = preparedStatement.executeQuery()) {

            // 处理结果集
            while (resultSet.next()) {
                targetTablePanel.add(new JCheckBox(resultSet.getString("table_name")));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        // 4更新面板
        targetTablePanel.revalidate();
        targetTablePanel.repaint();
    }

    /**
     * 全量同步表数据
     */
    private void fullSync() {
        // 1获取选中的库表
        DataSource sourceDS = (DataSource) sourceConnCombo.getSelectedItem();
        String sourceDBName = (String) sourceDBCombo.getSelectedItem();

        List<String> sourceTBs = new ArrayList<>();
        for (int i = 0; i < sourceTablePanel.getComponentCount(); i++) {
            JCheckBox selectedTB = (JCheckBox) sourceTablePanel.getComponent(i);
            if (selectedTB.isSelected()) {
                sourceTBs.add(selectedTB.getText());
            }
        }

        // 2获取目标库
        DataSource targetDS = (DataSource) targetConnCombo.getSelectedItem();
        String targetDBName = (String) targetDBCombo.getSelectedItem();


        // 3记录任务
        long taskId = idGenerator.snowflakeId();
        executor.submit(new RecordDataXTaskInfo(sourceDS, targetDS, sourceTBs, dataXTaskInfoMapper, taskId));

        // 4开始同步
        if (sourceDS == null || sourceDBName == null || targetDS == null || targetDBName == null) {
            JOptionPane.showMessageDialog(null, "检查源数据源和目标数据源设置完整性！", "结果", JOptionPane.ERROR_MESSAGE);
            return;
        }

        // 弹出对话框来展示同步进度信息
        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setVisible(true);
        threadDataKeeper.setProgressDialog(progressDialog);

        // 同步数据（异步）
        Reader reader = new Reader(sourceDS, sourceDBName, sourceTBs, threadDataKeeper); // 读线程
        executor.execute(reader);

        Writer writer = new Writer(targetDS, targetDBName, threadDataKeeper, progressDialog, taskId); // 写线程
        executor.execute(writer);

        progressDialog.setProcessedText(0, sourceTBs.size());
        progressDialog.setTotalTable(sourceTBs.size());
        log.info("开始同步===> 数据源：{}，选中的库名：{}，选中的库表：{}", sourceDS, sourceDBName, sourceTBs);
        log.info("目标数据源：{}，目标库名：{}", targetDS, targetDBName);
    }

    /**
     * 增量同步
     */
    private void increaseSync() {
        incrementalSyncDialog.setVisible(true);
    }

    public static void main(String[] args) {
        // 创建并显示数据迁移界面
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DataSyncUI().setVisible(true);
            }
        });
    }
}




